package hnet

import (
	"errors"
	"fmt"
	"haruhi/hiface"
	"haruhi/utils"
	"io"
	"net"
	"sync"
)

type Connection struct {
	// 当前TCP属于哪个Server
	TcpServer hiface.IServer
	// 当前连接的socket TCP 套接字
	Conn *net.TCPConn
	// 连接的ID
	ConnID uint32
	// 当前的连接状态
	isClosed bool
	// 告知当前连接已经退出/停止的channel
	ExitBuffChan chan bool
	// 消息管理模块
	MsgHandler hiface.IMsgHandle
	// 无缓冲管道, 用于读、写两个 goroutine 之间的消息通信
	msgChan chan []byte
	// 无缓冲管道, 用于读、写两个 goroutine 之间的消息通信
	msgBuffChan chan []byte
	// 连接属性
	property map[string]interface{}
	// 连接属性的锁
	propertyLock sync.RWMutex
}

// 初始化连接模块的方法
func NewConnection(server hiface.IServer, conn *net.TCPConn, connID uint32, msgHandler hiface.IMsgHandle) *Connection {
	c := &Connection{
		Conn:         conn,
		ConnID:       connID,
		MsgHandler:   msgHandler,
		isClosed:     false,
		ExitBuffChan: make(chan bool, 1),
		msgChan:      make(chan []byte),
		TcpServer:    server,
		msgBuffChan:  make(chan []byte, utils.GlobalObject.MaxMsgChanLen),
		property:     make(map[string]interface{}), //对链接属性map初始化
	}
	c.TcpServer.GetConnManager().Add(c)
	return c
}

// 写消息 goroutine , 用户将数据发送给客户端
func (c *Connection) StartWriter() {
	fmt.Println("[Writer Goroutine is running]")
	defer fmt.Println(c.RemoteAddr().String(), " [conn Writer exit!]")

	for {
		select {
		case data := <-c.msgChan:
			// 有数据要写给客户端
			if _, err := c.Conn.Write(data); err != nil {
				fmt.Println("Send Data error: ", err, " , Conn Writer exit!")
				return
			}
		case data, ok := <-c.msgBuffChan:
			if ok {
				if _, err := c.Conn.Write(data); err != nil {
					fmt.Println("Send buff data error : ", err, " , Conn write exit")
					return
				}
			} else {
				fmt.Println("msgBuffChan is closed")
				break
			}
		case <-c.ExitBuffChan:
			return
		}
	}
}

// 读业务方法
func (c *Connection) StartReader() {
	fmt.Println("[Reader Goroutine is running]")
	defer fmt.Println("connID = ", c.ConnID, " Reader is exit, remote addr is ", c.RemoteAddr().String())
	defer fmt.Println(c.RemoteAddr().String(), " [conn Reader exit!]")
	defer c.Stop()

	for {
		// 创建拆包的对象
		dp := &DataPack{}

		headData := make([]byte, dp.GetHeadLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil {
			fmt.Println("read msg head error ", err)
			return
		}

		// 拆包
		msg, err := dp.Unpack(headData)
		if err != nil {
			fmt.Println("unpack error ", err)
			return
		}

		// 根据 dataLen, 读取data
		var data []byte
		if msg.GetDataLen() > 0 {
			data = make([]byte, msg.GetDataLen())
			if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
				fmt.Println("read msg data error ", err)
				return
			}
		}
		msg.SetData(data)

		req := Request{
			conn: c,
			msg:  msg,
		}

		if utils.GlobalObject.WorkerPoolSize > 0 {
			// 已经启动工作池机制, 将消息发给 worker 处理
			c.MsgHandler.SendMsgToTaskQueue(&req)
		} else {
			// 从路由中，找到注册绑定的Conn对应的router调用
			go c.MsgHandler.DoMsgHandler(&req)
		}

	}
}

// 启动，准备开始工作
func (c *Connection) Start() {
	fmt.Println("Conn Start... ConnID = ", c.ConnID)

	// 启动从当前连接读数据的业务
	go c.StartReader()

	// TODO 启动从当前连接写数据的业务
	go c.StartWriter()

	c.TcpServer.CallOnConnStart(c)

	for {
		select {
		case <-c.ExitBuffChan:
			return
		}
	}
}

// 停止，结束工作
func (c *Connection) Stop() {
	fmt.Println("Conn Stop()... ConnID = ", c.ConnID)

	// 已经关闭，直接返回
	if c.isClosed {
		return
	}
	c.isClosed = true

	c.TcpServer.CallOnConnStop(c)

	// 关闭socket连接
	c.Conn.Close()
	c.ExitBuffChan <- true

	c.TcpServer.GetConnManager().Remove(c)
	// 回收资源
	close(c.msgBuffChan)
	close(c.ExitBuffChan)
}

// 获取当前连接的绑定 socket conn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

// 获取当前连接模块的连接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

// 获取远程客户端的TCP状态
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

// 发送数据
func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.isClosed {
		return errors.New("connection closed when send msg")
	}

	//将data封包，并且发送
	dp := NewDataPack()
	msg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("pack error msg id = ", msgId)
		return errors.New("pack error msg")
	}

	// 写回客户端
	c.msgChan <- msg

	return nil
}

// 发送数据
func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error {
	if c.isClosed {
		return errors.New("Connection closed when send buff msg")
	}
	dp := NewDataPack()
	msg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("pack error msg id = ", msgId)
		return errors.New("pack error msg")
	}

	// 写回客户端
	c.msgBuffChan <- msg

	return nil
}

func (c *Connection) SetProperty(key string, value interface{}) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	c.property[key] = value
}

func (c *Connection) GetProperty(key string) (value interface{}, err error) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	if value, ok := c.property[key]; ok {
		return value, nil
	} else {
		return nil, errors.New("No property found!")
	}
}

func (c *Connection) RemoveProperty(key string) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	delete(c.property, key)
}
